
/**
 * Classe criada para representar uma formiga<br/>
 * Especificaes : <br/>
 * -Deve conter um trajeto <br/>
 * -Deve ser capaz de interpretar um comando <code>Order</code> e/ou retornar
 * este comando </br> -Deve informar o seu destino para que outras no o sigam
 * </br> -
 * 
 * 
 * @author Edgard
 * @since 01/11/2011
 */
public class Ant implements Comparable<Ant> {
	private static int idCount = 0;
	private static int idDirection = 0;
	/**
	 * Alvo para esta formiga
	 */
	private Tile target;
	private int id = ++idCount;
	Tile currentTile, destination;
	Aim direction;
	int col, row;
	boolean isActive = false, canMove = false;

	/**
	 * Inicia a formiga com as informaes passadas.
	 * 
	 * @author edgardleal
	 * @since 02/11/2011
	 * @param tile
	 * @param direction
	 */
	public Ant(Tile tile, Aim direction) {
		this.currentTile = tile;
		this.direction = direction;
		row = tile.getCol();
		col = tile.getRow();
		init();
	}

	/**
	 * Retorna um nmero que identifica esta instano da classe Ant;
	 * 
	 * @return
	 */
	public int getId() {
		return id;
	}

	/**
	 * 
	 * @author edgardleal
	 * @since 02/11/2011
	 * @param tile
	 */
	public Ant(Tile tile) {
		this.currentTile = tile;
		col = tile.getCol();
		row = tile.getRow();
		idDirection++;
		idDirection = idDirection % 4;
		switch (idDirection) {
		case 1:
			direction = Aim.NORTH;
			break;
		case 2:
			direction = Aim.SOUTH;
			break;
		case 3:
			direction = Aim.WEST;
			break;
		default:
			direction = Aim.EAST;
		}
		init();
	}

	public static void main(String[] args) {
		Ant ant = new Ant(new Tile(10, 10));
		Ant ant1 = new Ant(new Tile(10, 10));
		Ant ant2 = new Ant(new Tile(10, 10));

		System.out.println(ant + " direction : " + ant.getDirection());
		System.out.println(ant1 + " direction : " + ant1.getDirection());
		System.out.println(ant2 + " direction : " + ant2.getDirection());

	}

	public boolean isActive() {
		return isActive;
	}

	public void setActive(boolean isActive) {
		this.isActive = isActive;
	}

	public boolean isCanMove() {
		return canMove;
	}

	public void setCanMove(boolean canMove) {
		this.canMove = canMove;
	}

	private void init() {
		isActive = true;
	}

	/**
	 * Atualiza a formiga atual de acordo com a direo informada no comando
	 * {@link Aim} informado
	 * 
	 * @author edgardleal
	 * @since 02/11/2011
	 */
	public void doTurn() {
		// TODO: faltando implementar
	}

	public int getCol() {
		return col;
	}

	public int getRow() {
		return row;
	}

	public Aim getDirection() {
		return this.direction;
	}

	@Override
	public boolean equals(Object obj) {
		if (obj instanceof Ant) {
			Ant ant = (Ant) obj;
			return ant.getCol() == col && ant.getRow() == row;
		} else if (obj instanceof Tile) {
			Tile tile = (Tile) obj;
			return tile.getCol() == col && tile.getRow() == row;
		}
		return false;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.lang.Comparable#compareTo(java.lang.Object)
	 */
	@Override
	public int compareTo(Ant ant) {
		return getCol() > ant.getCol() ? 1 : (getCol() == ant.getCol()
				&& getRow() == ant.getRow() ? 0 : -1);
	}

	/**
	 * Retorna a distancia entre esta formiga e o {@link Tile} informado
	 * 
	 * @author edgardleal
	 * @since 02/11/2011
	 * @param tile
	 * @return
	 */
	public double getDistance(Tile tile) {
		return new Vector(this.col, this.row, tile.getCol(), tile.getRow())
				.getDistance();
	}

	public void setDirection(Aim direction) {
		this.direction = direction;
	}

	/**
	 * Retorna um boolean dizendo se esta formiga se movimentara ou no
	 * 
	 * @author edgardleal
	 * @since 02/11/2011
	 * @return
	 */
	public boolean getOrder(Ants ants) {
		if (currentTile == null || direction == null)
			return false;
		try {
			Ilk ilk = ants.getIlk(currentTile);
			canMove = ilk.isPassable() && ilk.isUnoccupied();

			if (!canMove) {
				direction = getNewDirection(ants);
				canMove = direction != null;
			}
			isActive = false;// caso a movimentao tenha sucesso , devera
			// tornar-se true
			if (canMove)
				move();
			return canMove && direction != null;// newDirection pode retornar
			// null
		} catch (Exception ex) {
			ex.printStackTrace();
			return false;
		}
	}

	private void log(String message) {
		Logger.log(message);
	}

	public Tile getTile() {
		return currentTile;
	}

	/**
	 * Mtodo interno utilizado apenas para atuzlizar a posio das formigas.
	 * 
	 * @author edgardleal
	 */
	private void move() {
		// log("before move : " + this);
		col += direction.getColDelta();
		row += direction.getRowDelta();
		// log("after move : " + this);
	}

	/**
	 * Verifica uma direo alternativa , caso encontre retorna esta direo
	 * {@link Aim} caso </br> no encontre, retorna null.
	 * 
	 * @author edgardleal
	 * @since 02/11/2011
	 * @param ants
	 * @return
	 */
	private Aim getNewDirection(Ants ants) {
		Ilk ilk = null;
		for (Aim aim : Aim.values()) {
			ilk = ants.getIlk(ants.getTile(currentTile, aim));
			if (aim != direction && ilk.isPassable() && ilk.isUnoccupied()) {
				return aim;
			}
		}
		ilk = ants.getIlk(currentTile, direction);
		if (ilk.isPassable() && ilk.isUnoccupied()) {
			return direction;
		}
		return null;
	}

	public String toString() {
		return "id : " + id + " ,X: " + col + " ,Y: " + row;
	}

	public Tile getTarget() {
		return target;
	}

	public void setTarget(Tile target) {
		this.target = target;
	}

	private Aim reverseDirection(Aim aim) {
		Aim result;
		switch (aim) {
		case NORTH:
			result = Aim.SOUTH;
			break;
		case SOUTH:
			result = Aim.NORTH;
			break;
		case EAST:
			result = Aim.WEST;
			break;
		default:
			result = Aim.EAST;
			break;
		}
		return result;
	}

}
